{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kxu1Gfhx1pHg"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/jeffheaton/app_generative_ai/blob/main/t81_559_class_10_3_streamlit_state.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZbNbAV281pHh"
      },
      "source": [
        "# T81-559: Applications of Generative Artificial Intelligence\n",
        "**Module 10: StreamLit**\n",
        "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/Programs/Pages/default.aspx)\n",
        "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HwnvSYEQ1pHi"
      },
      "source": [
        "# Module 10 Material\n",
        "\n",
        "Module 10: StreamLit\n",
        "\n",
        "* Part 10.1: Running StreamLit in Google Colab [[Video]]() [[Notebook]](t81_559_class_10_1_streamlit.ipynb)\n",
        "* Part 10.2: StreamLit Introduction [[Video]]() [[Notebook]](t81_559_class_10_2_streamlit_intro.ipynb)\n",
        "* **Part 10.3: Understanding Streamlit State** [[Video]]() [[Notebook]](t81_559_class_10_3_streamlit_state.ipynb)\n",
        "* Part 10.4: Creating a Chat Application [[Video]]() [[Notebook]](t81_559_class_10_4_chat.ipynb)\n",
        "* Part 10.5: MultiModal Chat Application [[Video]]() [[Notebook]](t81_559_class_10_5_chat_multimodal.ipynb)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XLFov09h18yC"
      },
      "source": [
        "# Google CoLab Instructions\n",
        "\n",
        "The following code ensures that Google CoLab is running and maps Google Drive if needed."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AWGARRT92DrA"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "try:\n",
        "    from google.colab import drive, userdata\n",
        "    COLAB = True\n",
        "    print(\"Note: using Google CoLab\")\n",
        "except:\n",
        "    print(\"Note: not using Google CoLab\")\n",
        "    COLAB = False\n",
        "\n",
        "# OpenAI Secrets\n",
        "if COLAB:\n",
        "    os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')\n",
        "\n",
        "# Install needed libraries in CoLab\n",
        "if COLAB:\n",
        "    !pip install langchain openai streamlit"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v2MPPX0c1pHi"
      },
      "source": [
        "# Part 10.3: Understanding Streamlit State\n",
        "\n",
        "Streamlit is a powerful framework for building interactive web applications in Python. However, as you build more dynamic and complex apps, you may encounter the need to retain information between user interactions, such as keeping track of previous inputs, storing calculations, or remembering selections. This is where Streamlit's state management becomes essential.\n",
        "\n",
        "In Streamlit, state refers to the mechanism for storing and managing data during a user's session. Without state management, each interaction (like clicking a button or changing an input) triggers the entire app to rerun, resetting any values you may want to preserve. State allows you to keep these values intact, enabling more advanced and responsive behaviors in your app.\n",
        "\n",
        "### How Streamlit Handles State\n",
        "Streamlit offers a simple way to handle state through st.session_state, a special object that persists values during a user’s session. This object works like a dictionary where you can store, update, and retrieve values across different parts of your app. By using session state, you can:\n",
        "\n",
        "* Retain user input values when navigating through different components of your app.\n",
        "* Store results of calculations or user choices to be used or modified in subsequent interactions.\n",
        "* Build more complex apps that involve multiple steps, data processing, and interactivity.\n",
        "\n",
        "## The Power of Streamlit State: A Loan Calculator Example\n",
        "In this module, we will explore state management using a loan amortization calculator as a practical example. This app allows users to input various loan parameters, perform calculations, and store the results in session state for easy comparison. By leveraging state management, the app enables users to explore different loan scenarios without losing their previous calculations, offering a richer, more interactive experience.\n",
        "\n",
        "Before diving into the specifics of the loan calculator example, we'll first cover the basics of how to use st.session_state effectively in Streamlit applications. This foundation will provide the knowledge needed to implement more advanced features and make your apps truly dynamic.\n",
        "\n",
        "Let's get started by understanding how st.session_state works and how it can be utilized to maintain information across different parts of a Streamlit app.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gA3YGzPOZD_e"
      },
      "outputs": [],
      "source": [
        "%%writefile app.py\n",
        "\n",
        "import streamlit as st\n",
        "import pandas as pd\n",
        "\n",
        "# Function to calculate loan amortization\n",
        "def calculate_amortization(loan_amount, annual_rate, years):\n",
        "    monthly_rate = annual_rate / 12 / 100\n",
        "    num_payments = years * 12\n",
        "    monthly_payment = loan_amount * (monthly_rate * (1 + monthly_rate) ** num_payments) / ((1 + monthly_rate) ** num_payments - 1)\n",
        "\n",
        "    # Create amortization schedule\n",
        "    amortization_data = []\n",
        "    balance = loan_amount\n",
        "    total_interest = 0\n",
        "    for i in range(1, num_payments + 1):\n",
        "        interest_payment = balance * monthly_rate\n",
        "        principal_payment = monthly_payment - interest_payment\n",
        "        balance -= principal_payment\n",
        "        total_interest += interest_payment\n",
        "        amortization_data.append([i, monthly_payment, principal_payment, interest_payment, max(balance, 0)])\n",
        "\n",
        "    # Create DataFrame\n",
        "    df = pd.DataFrame(amortization_data, columns=['Month', 'Payment', 'Principal', 'Interest', 'Balance'])\n",
        "    return df, monthly_payment, total_interest\n",
        "\n",
        "# Initialize session state to store calculations\n",
        "if 'calculations' not in st.session_state:\n",
        "    st.session_state['calculations'] = []\n",
        "\n",
        "# Streamlit App\n",
        "st.title('Loan Amortization Calculator')\n",
        "\n",
        "# Input Fields\n",
        "loan_amount = st.number_input('Loan Amount', value=300000.0, min_value=0.0, step=1000.0)\n",
        "annual_rate = st.number_input('Annual Interest Rate (%)', value=7.5, min_value=0.0, step=0.1)\n",
        "years = st.number_input('Loan Term (years)', value=30, min_value=1, step=1)\n",
        "\n",
        "# Calculate amortization table\n",
        "if st.button('Calculate Amortization Table'):\n",
        "    amortization_df, monthly_payment, total_interest = calculate_amortization(loan_amount, annual_rate, years)\n",
        "    st.write(f'Monthly Payment: ${monthly_payment:,.2f}')\n",
        "    st.write(f'Total Interest Paid: ${total_interest:,.2f}')\n",
        "    st.dataframe(amortization_df)\n",
        "\n",
        "    # Save the current calculation to session state\n",
        "    st.session_state['calculations'].append({\n",
        "        'Loan Amount': loan_amount,\n",
        "        'Annual Rate (%)': annual_rate,\n",
        "        'Years': years,\n",
        "        'Monthly Payment': monthly_payment,\n",
        "        'Total Interest': total_interest\n",
        "    })\n",
        "\n",
        "# Display saved calculations\n",
        "if st.session_state['calculations']:\n",
        "    st.subheader('Saved Loan Calculations')\n",
        "    comparison_df = pd.DataFrame(st.session_state['calculations'])\n",
        "    st.dataframe(comparison_df)\n",
        "\n",
        "    # Downloadable CSV of all saved calculations\n",
        "    csv = comparison_df.to_csv(index=False)\n",
        "    st.download_button(label=\"Download Comparison Table as CSV\", data=csv, file_name='loan_comparisons.csv', mime='text/csv')\n",
        "\n",
        "    # Clear all calculations\n",
        "    if st.button('Clear All Calculations'):\n",
        "        st.session_state['calculations'].clear()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "\n",
        "The code provided demonstrates how to use Streamlit's session state to create an interactive loan amortization calculator that allows users to compare multiple loan scenarios. The app starts by defining a function to calculate the amortization schedule for a given loan amount, interest rate, and loan term. The main part of the app initializes the session state, creating a list to store loan calculations. This list is crucial for persisting user data throughout their interaction with the app.\n",
        "\n",
        "When the user inputs loan parameters and clicks the \"Calculate Amortization Table\" button, the app computes the monthly payment and total interest using the specified values. These results are then stored in the session state list as a dictionary containing the loan amount, interest rate, loan term, monthly payment, and total interest. This allows the app to save each new calculation without losing previously entered data.\n",
        "\n",
        "The app checks if there are any saved calculations in the session state. If present, it displays a comparison table showing all the stored loan scenarios, including the loan amount, interest rate, term, monthly payment, and total interest. Additionally, it provides a \"Download Comparison Table as CSV\" button, allowing users to download their comparison data for further analysis. A \"Clear All Calculations\" button is also included, which clears the session state, resetting the app to its initial state. This code highlights the power of st.session_state to build a more interactive and user-friendly app by preserving information across multiple user interactions.\n",
        "\n",
        "Next, we obtain the password for our StreamLit server we are about to launch.\n"
      ],
      "metadata": {
        "id": "GWNmAgVuba_O"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!curl https://loca.lt/mytunnelpassword\n"
      ],
      "metadata": {
        "id": "nUaNcodZbdoO"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "We launch the StreamLit server and obtain its URL. You will need the above password when you access the URL it gives you."
      ],
      "metadata": {
        "id": "m9hk-1zAbgGn"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!streamlit run app.py server1 &>/content/logs.txt &\n",
        "!npx --yes localtunnel --port 8501"
      ],
      "metadata": {
        "id": "BgvEx3Yubk6X"
      },
      "execution_count": null,
      "outputs": []
    }
  ],
  "metadata": {
    "anaconda-cloud": {},
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.4"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}